// gulp-sass模块进行scss的压缩编译 yarn add gulp-sass --dev 使用淘宝镜像 
// gulp-babel模块进行js的编译  yarn add gulp-babel --dev
// 安装babel相关文件  yarn add @babel/core @babel/preset-env --dev
// gulp-swig 网页模板引擎 yarn add gulp-swig --dev
// gulp-imagemin 图片压缩插件 yarn add gulp-imagemin --dev
// del 插件用于自动清除dist目录下的文件
// gulp-load-plugins 用于自动加载插件
// browser-sync 热部署服务器 自动热更新
// gulp-useref 插件 自动处理html当中的构建注释 将使用文件打包到一个文件路径当中
// yarn add gulp-useref --dev
// gulp-htmlmin 压缩html  gulp-uglify 压缩js  gulp-clean-css 压缩css
// yarn add gulp-htmlmin gulp-uglify gulp-clean-css --dev
// gulp-if 用于判断文件类型 yarn add gulp-if --dev
// 上述命令不成功则使用 cnpm i --save-dev [插件名字]

// temp为临时任务文件 中间有useref压缩 dist为最终项目文件

// src-输出流 dest-输入流 parallel-并行任务 series-串行任务 watch-监听任务
const { src, dest, parallel, series, watch } = require('gulp')
// const sass = require('gulp-sass')
// const babel = require('gulp-babel')
// const swig = require('gulp-swig')
// const imagemin = require('gulp-imagemin')

const del = require('del')
const browserSync = require('browser-sync')

const loadPlugins = require('gulp-load-plugins')

// 插件成为对象下的一个属性
const plugins = loadPlugins()
// 自动创建一个开发服务器
const bs = browserSync.create()

// 命令行当前工作目录
const cwd = process.cwd()

// 载入项目位置文件
let config = {
 // defaule config
  build: {
      src: 'src',
      dist: 'dist',
      temp: 'temp',
      public: 'public',
      paths: {
        styles: 'assets/styles/*.scss',
        scripts: 'assets/scripts/*.js',
        pages: '*.html',
        images: 'assets/images/**',
        fonts: 'assets/fonts/**'
    }
  }
}

// 页面模板内的数据
try {
  // 文件内的数据
  const loadConfig = require(`${cwd}/pages.config.js`)
  // 页面数据
  config = Object.assign({}, config, loadConfig)
}catch (e) {

}

// 清除生成文件 可导出
const clean = () => {
  // 放入任意文件清除目录
  return del([config.build.dist, config.build.temp])
}

// 样式编译  不需要导出
// 私有函数 使用输入输出api
const style = () => {
  // src指定输出流文件 base保存目录基准结构 src开始
  return src(config.build.paths.styles, { base: config.build.src, cwd: config.build.src })
    // 默认_开头文件为依赖文件 会被忽略  outputStyle 使得属性完全展开
    // .pipe(sass({ outputStyle:'expanded' }))
    .pipe(plugins.sass({ outputStyle: 'expanded' }))
    // dest指定输入流地址
    .pipe(dest(config.build.temp))
    .pipe(bs.reload({ stream: true }))
}

// 脚本编译  不需要导出
const script = () => {
  return src(config.build.paths.scripts, { base: config.build.src, cwd: config.build.src })
    // 配置js编译转换的最新版本 不设置presets则无分别
    // .pipe(babel({ presets: ['@babel/preset-env'] }))
    .pipe(plugins.babel({ presets: [require('@babel/preset-env')] }))
    .pipe(dest(config.build.temp))
    // 重新加载到浏览器
    .pipe(bs.reload({ stream: true }))
}

// 页面编译  不需要导出
const page = () => {
  // 子文件夹也有html文件时使用通配符
  return src(config.build.paths.pages, { base: config.build.src, cwd: config.build.src })
    // 将页面模板内的数据写入
    // .pipe(swig({ data }))
    .pipe(plugins.swig({ data: config.data, defaults: { cache: false } })) // 防止模板缓存导致页面不能及时更新
    .pipe(dest(config.build.temp))
    .pipe(bs.reload({ stream: true }))
}

// 图片转换  不需要导出
const image = () => {
  return src(config.build.paths.images, { base: config.build.src, cwd: config.build.src })
    // .pipe(imagemin())
    .pipe(plugins.imagemin())
    .pipe(dest(config.build.dist))
}

// 字体文件编译  不需要导出
const font = () => {
  return src(config.build.paths.fonts, { base: config.build.src, cwd: config.build.src })
    .pipe(plugins.imagemin())
    .pipe(dest(config.build.dist))
}

// 其他额外的文件拷贝 不需要导出
const extra = () => {
  return src('**', { base: config.build.public, cwd: config.build.public })
    .pipe(dest(config.build.dist))
}

// 服务器/文件监听配置  不需要导出
const serve = () => {
  // 第一个参数为监听的目标 第二个参数为监听目标变化后执行的函数
  watch(config.build.paths.styles, { cwd: config.build.src} , style)
  watch(config.build.paths.scripts, { cwd: config.build.src} , script)
  watch(config.build.paths.pages, { cwd: config.build.src} , page)
  // 仅是压缩 发布时为静态文件
  // watch('src/assets/images/**', image)
  // watch('src/assets/fonts/**', font)
  // watch('public/**', extra)

  // 静态文件变化则页面重新加载
  watch([
    config.build.paths.images,
    config.build.paths.fonts,
  ], { cwd: config.build.src } , bs.reload)

  watch('**', { cwd: config.build.publics } , bs.reload)

  // 初始化服务器相关配置
  bs.init({
    // 右上角提示关掉
    notify: false,
    // 服务器端口
    port: 2080,
    // 是否自动打开浏览器
    // open: false,
    // 监听的目录文件 可以及时更新页面
    // files: 'dist/**',
    server: {
      // 指定网站根目录 依次往后寻找目录  开发阶段静态资源访问源文件 提高构建效率
      baseDir: [config.build.temp, config.build.dist, config.build.public],
      // 对于 请求路由 做映射 不能在线上使用
      routes: {
        '/node_modules': 'node_modules'
      }
    }
  })
}

// 构建注释以及文件压缩  不需要导出
const useref = () => {
  // src输出流 中的已编译后的html文件
  return src(config.build.paths.pages, { base: config.build.temp, cwd: config.build.temp })
    // 构建注释 <!-- build --> <!-- endbuild -->
    // 转换流 把构建注释做转换 将构建注释打包成一个文件 并替代源文件路径
    .pipe(plugins.useref({ searchPath: [config.build.temp, '.'] }))
    // 压缩的文件  html js css
    // 判断读取流当中的文件类型 使用正则匹配文件  匹配正确则执行任务
    // 存在问题 边读边写  产生读取文件写不进去的情况
    .pipe(plugins.if(/\.js$/, plugins.uglify()))
    .pipe(plugins.if(/\.css$/, plugins.cleanCss()))
    // 默认仅压缩空格
    // 根据文档做其他配置
    .pipe(plugins.if(/\.html$/, plugins.htmlmin({
      // 折叠换行符
      collapseWhitespace: true,
      // 压缩html内syle的css
      minifyCSS: true,
      // 压缩html内script的js
      minifyJS: true
    })))
    // 生成一个文件
    .pipe(dest(config.build.dist))
}

// 不需要导出 build中有执行
// 使用组合任务 并行执行style script page image font
const compile = parallel(style, script, page)

// 上线之前执行的任务   需要导出
const build =  series( 
  // 先清除文件再去生成
  clean,
  parallel(
    // 编译后压缩
    series(compile, useref),
    image,
    font,
    extra
  )
)


// 需要导出
// 开发任务 先转换编译文件 再进行热部署 不需要dist
const develop = series(compile, serve)

module.exports = {
  clean,
  // compile,
  build,
  // serve,
  develop,
  // useref
}
